package com.sikaryofficial.backend.aspect;

import com.sikaryofficial.backend.annotation.Repeat;
import com.sikaryofficial.common.core.exception.ServiceException;
import com.sikaryofficial.common.core.utils.ip.IpUtils;
import com.sikaryofficial.common.redis.service.RedisService;
import com.sikaryofficial.common.security.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
@Slf4j
public class NoRepeatAop {
    @Autowired
    private RedisService redisService;

    /**
     * 定义切入点
     */
    @Pointcut("@annotation(com.sikaryofficial.backend.annotation.Repeat)")
    public void noRepeat() {}

    /**
     * 前置通知：在连接点之前执行的通知
     * @param point
     */

    @Around("noRepeat()")
    public Object before(ProceedingJoinPoint point) {
        // 如果是登录用户，则不限制访问频次
        if(Objects.nonNull(SecurityUtils.getUserId())){
            try {
                return point.proceed();
            } catch (Throwable e) {
                e.printStackTrace();
                throw new ServiceException(e.getMessage());
            }
        }
        // 接收到请求，记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        HttpServletRequest request = attributes.getRequest();
        // 此处可以用token或者JSessionId
        String ip = IpUtils.getIpAddr(request);
        //请求路径请求参数
        StringBuilder path = new StringBuilder(request.getServletPath());
        Map<String, String[]> maps =  request.getParameterMap();
        for (Map.Entry<String, String[]> entry : maps.entrySet()) {
            path.append(entry.getKey()).append(":").append(Arrays.toString(entry.getValue())).append(";");
        }
        String key ="hismk:noRepeat:"+ip + path;
        // 获取注解
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        Repeat annotation = method.getAnnotation(Repeat.class);
        long timeout = annotation.value();
        Boolean hasSubmitted = redisService.setIfAbsentCacheObject(key, key, timeout, TimeUnit.SECONDS);
        log.info("noRepeat--NoRepeatSubmitAop.key: {}",key,hasSubmitted);
        log.info("noRepeat--NoRepeatSubmitAop.hasSubmitted:{}",hasSubmitted);
        if (Boolean.TRUE.equals(hasSubmitted)) {
            try {
                return point.proceed();
            } catch (Throwable e) {
                log.error("执行错误{}--NoRepeatSubmitAop.before",key,e);
                throw new ServiceException(e.getMessage());
            }
        }else {
            log.error("重复请求{}--NoRepeatSubmitAop.before",key);
            throw new ServiceException("repeat request");
        }
    }
}
